第 11 章:加密安全與權限控管
Authentication 與 Authorization 概念
- Authentication:你是誰?
- Authorization:你可以做什麼?
所有 Kubernetes 叢集都有兩種類型的使用者
- service accounts managed by Kubernetes, 程式(pod)連接 APIServer
- normal users. 普通用戶,例如透過 kubectl 連接 API Server
設定 Certificates and kubeconfig files
- kubeadm-based cluster will:
- create self-signed Certificate Authority (in /etc/kubernetes/pki)
- ca.key private key
- ca.crt CA Certificate
- 會被複製到各個 cluster 節點上,讓 node 信任由這個 CA 簽名的證書。(同時也在 kubeconfig 文件裡)
- create self-signed Certificate Authority (in /etc/kubernetes/pki)
- Generates Certificates for System Components
- kubernetes-admin User created
建立 Certificate
- Create new Certificate for new user
- Create a private key with openssl
- Create a Certificate signing request with openssl
- Create and submit
CertificateSigning
Request object - Approve the
CertificateSigning
Request - Retrieve the Certificate
$ # create a private key
$ openssl genrsa -out demouser.key 2048# generate CSR
$ # CN(common name) is your username, o(Organization) is the Group
$ openssl req -new -key demouser.key -out demouser.csr -subj "/CN=demouser"
$ # the CertificateSigning Request needs to be base64 encoded
$ cat demouser.csr | base64 | tr -d "\n"`
Create CertificateSigning
Request object
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: demouser
spec:
groups:
- system:authenticated
request: put the base64 encoded csr here
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
Approve CertificateSigning
Requst object
$ # approe the CSR
$ kubectl certificate approve demouser
# retrieve the certificate from the CSR object, and decode it from base64
$ kubectl get certificatesigningrequests demouser -o jsonpath='{.status.certificate}' | base64 --decode > demouser.crt
$ # check certificate
$ openssl x509 -in demouser.crt -text
設定 kubeconfig files
- 位址:
/etc/kubernetes/admin.conf
- 內容
- Users
- Clusters
- Contexts
建立 demo 用戶
kubectl config set-credentials demouser --client-key=demouser.key --client-certificate=demouser.crt --embed-certs=true
查看 user
kubectl config get-users
建立 context
kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
kubernetes-admin@kubernetes kubernetes kubernetes-admin default
kubectl config set-context demo --user=demouser --cluster=kubernetes
Context "demo" created.
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
demo kubernetes demouser
kubernetes-admin@kubernetes kubernetes kubernetes-admin default
kubectl config use-context demo
Switched to context "demo".
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
demo kubernetes demouser
kubernetes-admin@kubernetes kubernetes kubernetes-admin default
kubectl get nodes
Error from server (Forbidden): nodes is forbidden: User "demouser" cannot list resource "nodes" in API group "" at the cluster scope
kubectl get nodes -v 6
I0711 20:58:04.364228 65356 loader.go:372] Config loaded from file: /home/vagrant/.kube/config
I0711 20:58:04.383605 65356 round_trippers.go:553] GET https://192.168.56.10:6443/api/v1/nodes?limit=500 403 Forbidden in 14 milliseconds
I0711 20:58:04.384119 65356 helpers.go:222] server response object: [{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "nodes is forbidden: User \"demouser\" cannot list resource \"nodes\" in API group \"\" at the cluster scope",
"reason": "Forbidden",
"details": {
"kind": "nodes"
},
"code": 403
}]
Error from server (Forbidden): nodes is forbidden: User "demouser" cannot list resource "nodes" in API group "" at the cluster scope
清理 context 與 user
kubectl config use-context kubernetes-admin@kubernetes
kubectl config delete-context demo
kubectl config delete-user demouser
Role Based Access Control 以角色為基礎的存取控制
- Role / ClusterRole 定義了可以做什麼
- RoleBinding / ClusterRoleBinding 定義了誰可以做在這個 Role / ClusterRole 定義
Roles 定義權限
Roles 代表的是可以對 k8s 的 resource 做什麼操作, 並且是分別 namespace 的
kubectl create role demorole --verb=get,list --resource=pods --namespace ns1
kubectl create role demorole --verb= --resource=pods --namespace ns1
ClusterRoles 定義權限
Cluster 層級的 Resource, Node、PersistentVolumes。 ( 跨 namespace )
kubectl create clusterrole democlusterrole --verb=get,list --resource=nodes
RoleBinding / ClusterRoleBinding 定義誰可以有權限
- RoleBinding
kubectl create rolebinding demorolebinding --role=demorole --user=demouser --namespace ns1
- ClusterRoleBinding
kubectl create clusterrolebinding democlusterrolebinding --clusterrole=democlusterrole --user=demouser
- /api (core group)
- 負責 K8S 集群運作的核心功能,像namespaces、Pods、RCs、Nodes、bindings、Secret、Service 等物件
- /apis (named group)
named group
相較於core group
更有組織性,像是/apps、/extension、/networking.k8s.io、/storage.k8s.io、authentication.k8s.io
Verb
包含:- list, get, create, delete, update, watch
- 如何查看有哪些
API Group
呢?- 可以透過
curl https://localhost:6443 -k
指令- 需要加上https需要的參數,在指令後方加上
-key
、-cert
及-cacert
參數即可 - 透過
kubectl proxy
命令,在 Control Plane 節點上以 port 8001 啟動 kubectl proxy client。這種方式是直接參考 kubeconfig 檔案中 User 的 credentials 和 certificates
- 需要加上https需要的參數,在指令後方加上
- 第二種方法直接在
Control Plane
節點上輸入kubectl proxy
命令,再開另一視窗輸入curl http://localhost:8001 -k
這樣一來就可以看到有哪些API Group
是 avaliable的,若要特別查看哪些是named API Group,可以透過grep篩選
- 可以透過
curl http://localhost:8001/apis -k | grep -i "name"
使用場景
- Role / RoleBinding 一般用於單一 namespace 去定義權限
- ClusterRole / ClusterRoleBinding 一般用於所有的 namespace
Role and RoleBinding 測試
以管理員身分建立一些資源
kubectl config use-context kubernetes-admin@kubernetes
kubectl create namespace ns1
kubectl create deployment web1 --namespace=ns1 --image=gcr.io/google-samples/hello-app:1.0 --port=8080 --replicas=2# test
kubectl auth can-i list pod #yes
kubectl auth can-i list pod --as demouser #no
建立 role and role binding
kubectl create role demorole --verb=get,list --resource=pods --namespace ns1
kubectl create rolebinding demorolebinding --role=demorole --user=demouser --namespace n
測試權限
kubectl auth can-i list pod --as demouser #no
kubectl auth can-i list pod --as demouser --namespace ns1 #yes
kubectl get pods --namespace ns1 --as demouser
kubectl auth can-i delete pod --as demouser --namespace ns1 #no
kubectl auth can-i list node --as demouser --namespace ns1 #no
kubectl auth can-i list deployment --as demouser --namespace ns1 #no
建立 ClusterRole and ClusterRoleBinding
$ kubectl create clusterrole democlusterrole --verb=list --resource=node
clusterrole.rbac.authorization.k8s.io/democlusterrole created
$ kubectl create clusterrolebinding democlusteerrolebinding --clusterrole=democlusterrole --user=demouser
clusterrolebinding.rbac.authorization.k8s.io/democlusteerrolebinding created
$ kubectl auth can-i list node #yes
$ kubectl auth can-i list node --as demouser yes
Service Account 定義程式用權限
建立 ServiceAccount
kubectl create serviceaccount demosa
kubectl describe serviceaccounts demosa
建立包含 ServiceAccount 的 Pod
serviceacc.yaml
apiVersion: v1
kind: Pod
metadata:
name: client
spec:
serviceAccount: demosa
containers:
- name: client
image: xiaopeng163/net-box:latest
command:
- sh
- -c
- "sleep 1000000"
查看 service account 的 token
kubectl describe pod client
透過 jsonpath 過濾
kubectl get pods client -o jsonpath='{.spec.containers[0].volumeMounts}' | python3 -m json.tool
[
{
"mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
"name": "kube-api-access-tvr98",
"readOnly": true
}
]
$ kubectl exec -it client -- sh
/omd #
/omd #
/omd # cd /var/run/secrets/kubernetes.io/serviceaccount
/run/secrets/kubernetes.io/serviceaccount # ls -l
total 0
lrwxrwxrwx 1 root root 13 Jul 16 14:15 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 Jul 16 14:15 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 Jul 16 14:15 token -> ..data/token
/run/secrets/kubernetes.io/serviceaccount #
ServiceAccount Authentication
驗證權限
kubectl exec -it client -- sh
/omd # cd /var/run/secrets/kubernetes.io/serviceaccount
/run/secrets/kubernetes.io/serviceaccount # TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
/run/secrets/kubernetes.io/serviceaccount # CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
/run/secrets/kubernetes.io/serviceaccount #
/run/secrets/kubernetes.io/serviceaccount # curl --cacert $CACERT -X GET https://kubernetes.default.svc.cluster.local/api{ "kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/api\"",
"reason": "Forbidden",
"details": {},
"code": 403}/run/secrets/kubernetes.io/serviceaccount #
/run/secrets/kubernetes.io/serviceaccount # curl --cacert $CACERT --header "Authorization: Bearer $TOKEN" -X GET https://kubernetes.default.svc.cluster.local/api{ "kind": "APIVersions",
"versions": [ "v1"
],
"serverAddressByClientCIDRs": [ { "clientCIDR": "0.0.0.0/0",
"serverAddress": "192.168.56.10:6443"
}
驗證訪問集群資源的權限
/run/secrets/kubernetes.io/serviceaccount # curl --cacert $CACERT --header "Authorization: Bearer $TOKEN" -X GET https://kubernetes.default.svc.cluster.local/api/v1/namespaces/default/pods?limit=500{ "kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:default:demosa\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
"reason": "Forbidden",
"details": { "kind": "pods"
},
"code": 403}/run/secrets/kubernetes.io/serviceaccount #
ServiceAccount Authorization
kubectl auth can-i list pods --as=system:serviceaccount:default:demos
I0716 14:46:05.735051 61770 loader.go:372] Config loaded from file: /home/vagrant/.kube/config
I0716 14:46:05.761522 61770 round_trippers.go:553] GET https://192.168.56.10:6443/api/v1/namespaces/default/pods?limit=500 403 Forbidden in 20 milliseconds
I0716 14:46:05.762209 61770 helpers.go:222] server response object: [{ "kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:default:demosa\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
"reason": "Forbidden",
"details": { "kind": "pods"
},
"code": 403}]
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:demosa" cannot list resource "pods" in API group "" in the namespace "default"
RBAC
建立 RBAC
$ kubectl create role demorole --verb=get,list --resource=pods
$ kubectl create rolebinding demorolebinding --role=demorole --serviceaccount=default:demosa
rolebinding.rbac.authorization.k8s.io/demorolebinding created
$ kubectl auth can-i list pods --as=system:serviceaccount:default:demosa
yes
進入到一個綁定此 service account 的 pod 進行測試
kubectl get nodes
$ kubectl exec -it client -- sh
/omd # cd /var/run/secrets/kubernetes.io/serviceaccount
/run/secrets/kubernetes.io/serviceaccount # TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
/run/secrets/kubernetes.io/serviceaccount # CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
/run/secrets/kubernetes.io/serviceaccount #
/run/secrets/kubernetes.io/serviceaccount # curl --cacert $CACERT --header "Authorization: Bearer $TOKEN" -X GET https://kubernetes.default.svc.cluster.local/api/v1/namespaces/default/pods?limit=500{ "kind": "PodList",
"apiVersion": "v1",
"metadata": { "resourceVersion": "1625465"
},
....
....
Security Context
它定義了Pod
或容器的特權和訪問控制設置。SecurityContext
包括:
-
Discretionary Access Control
訪問目標(如檔案)的權限基於User ID(UID)和 Group ID(GID)。
-
Security Enhanced Linux (SELinux)
為目標分配安全標籤
-
Running as privileged or unprivileged
以特權或非特權運行
-
Linux Capabilities
為某些 process 提供特權,但不是 root 的所有特權
-
AppArmor
使用程式配置文件來限制個別程式的功能。
-
Seccomp
過濾及篩選 process 的 system call
-
AllowPrivilegeEscalation
控制 process 是否可以比其 parent process 獲得更多的特權
-
readOnlyRootFilesystem
將容器的 root file system mount 為 Read-Only
在 Kubernetes
內也可以透過 SecurityContext
對每個 Container 去進行相關的權限設定。要為Pod指定安全設置,需在Pod YAML中加入securityContext
參數
cat security-context.yaml
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
securityContext:
allowPrivilegeEscalation: false
- runAsUser: 1000 對於
Pod
中的任何容器,所有 process 都已 User ID = 1000 運行 - runAsGroup: 3000
Pod
的任何容器內的所有 process 指定 primary group ID 為 3000。指定runAsGroup 時, User ID 1000 和 Group ID 3000 也將擁有所有創建的檔案。- K8s default primary group ID: root(0))
- fsGroup: 2000 容器的所有 process 也是 supplementary Group ID 2000 的一部分。Volume /data/demo 及該 Vloume 中所有檔案的擁有者均為 Group ID 2000。